package com.yunban.project.api.text_check.service.impl;

import com.alibaba.fastjson2.JSON;
import com.yunban.project.api.text_check.domain.CorrectionConfig;
import com.yunban.project.api.text_check.dto.coze.CozeUnifiedResp;
import com.yunban.project.api.text_check.service.AiCorrectionService;
import com.yunban.project.api.text_check.utils.CorrectUtils;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.exception.BusinessException;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: lijiajun
 * @date: 2024-11-22
 * @version: 1.0
 */
@Slf4j
@Service("baiduAiCorrectionService")
public class BaiduAiCorrectionService implements AiCorrectionService {

    @Resource
    private RestTemplate restTemplate;

    private static final String GET_TOKEN_REQUEST_URL = "https://aip.baidubce.com/oauth/2.0/token?client_id=%s&client_secret=%s&grant_type=client_credentials";

    String getAccessToken(CorrectionConfig config) {
        String url = String.format(GET_TOKEN_REQUEST_URL, config.getApiKey(), config.getApiSecret());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(headers);
        try {
            ResponseEntity<AccessTokenResp> exchangeResult = this.restTemplate.exchange(url, HttpMethod.POST, entity, AccessTokenResp.class);
            AccessTokenResp body = exchangeResult.getBody();
            log.info("获取百度千帆大模型token结果:{}", JSON.toJSONString(body));
            if (ObjectUtils.isEmpty(body)) {
                return null;
            }
            return body.getAccess_token();
        } catch (Exception e) {
            log.error("获取百度千帆大模型token异常:{}", e.getMessage());
            log.error("获取百度千帆大模型token异常", e);
            return null;
        }
    }

    @Override
    public String correction(String text, CorrectionConfig config, String taskId) {
        CorrectUtils.printStartTime(config.getCode());
        String sourceText = text;
        // 构建提示词
        text = config.getPromptPrefix() + text + config.getPromptSuffix();

        String accessToken = this.getAccessToken(config);
        if (!StringUtils.hasText(accessToken)) {
            log.info("获取百度千帆大模型token失败");
            return null;
        }
        log.info("百度千帆大模型token:{}", accessToken);

        //new一个请求体
        RequestMessage requestBody = new RequestMessage();
        //role标识用户  一个请求参数
        requestBody.addMessage(new Message("user", text));
        //将requestBody转为json字符串
        String requestParams = JSON.toJSONString(requestBody);
        //开启请求头
        HttpHeaders headers = new HttpHeaders();
        //设置请求头类型为json
        headers.setContentType(MediaType.APPLICATION_JSON);
        //设置请求头中的Authorization字段，携带认证信息
        headers.set("Authorization", "Bearer" + accessToken);
        log.info("请求百度千帆大模型对话请求参数:{}", requestParams);
        //HttpEntity封装http请求
        HttpEntity<String> entity = new HttpEntity<>(requestParams, headers);
        String url = String.format(config.getUrlPath() + "?access_token=%s", accessToken);
        //发起post请求  指定的响应类型为String字符串 此处带了url[token] entity[代表了请求参数请求头]
        //response是一个http响应[ResponseEntity]
        try {
            ResponseEntity<QianFanResponse> response = restTemplate.postForEntity(url, entity, QianFanResponse.class);
            //对它的code进行判断
            if (!response.getStatusCode().is2xxSuccessful()) {
                log.error("获取答案失败，HTTP状态码: {}", response.getStatusCode());
                return null;
            }
            QianFanResponse result = response.getBody();
            log.info("百度千帆大模型对话结果:{}", JSON.toJSONString(result));
            if (ObjectUtils.isEmpty(result) || !StringUtils.hasText(result.getResult())) {
                return null;
            }
            // 如果纠正后的数据 中前缀包含 "纠正后" 这三个字符，则代表纠正输出结果错误，则进行跳过
            if (result.getResult().contains("纠正后")) {
                log.info("BAIDU_API 纠正结果包含\"纠正后\"，跳过本次纠正");
                return null;
            }
            // 如果纠错后的输出格式中，不包含“输出：”“分类：”“来源：” 那么则跳过
            if (!result.getResult().contains("输出：") && !result.getResult().contains("分类：") && !result.getResult().contains("来源：")) {
                log.info("BAIDU_API 纠正结果不包含\"输出：\"\"分类：\"\"错误等级：\"\"来源：\"，跳过本次纠正");
                return null;
            }
            log.info("BAIDU_API 源文本01:{}", sourceText);
            log.info("BAIDU_API 纠错结果02:{}", result.getResult());
            log.info("BAIDU_API 纠错结果:{}", result.getResult());
            return this.formatResponse(result.getResult(), sourceText);
        } catch (Exception ex) {
            log.error("获取百度千帆大模型对话异常", ex);
            log.error("获取百度千帆大模型对话异常:{}", ex.getMessage());
            return null;
        } finally {
            CorrectUtils.printEndTime(config.getCode());
        }
    }

    @Data
    static class AccessTokenResp {
        private String refresh_token;
        private int expires_in;
        private String session_key;
        private String access_token;
        private String scope;
        private String session_secret;
        private String error_description;
        private String error;
    }

    @Data
    static class RequestMessage {
        /**
         * 聊天上下文
         */
        List<Message> messages = new ArrayList<>();

        /**
         * 范围(0~1.0]
         * 较高的数值会使输出更加随机
         */
        float temperature = Float.parseFloat("0.95");

        /**
         * 影响文本的多样性，取值越大生成的文本多样性越强
         * 建议该参数与temperature只设置一个。建议top_p和temperature不要同时更改
         */
        float top_p = Float.parseFloat("0.8");

        /**
         * 通过对已生成的token增加惩罚，减少重复生成的现象
         * 值越大，惩罚越大
         * 取值范围[1,2]
         */
        float penalty_score = Float.parseFloat("1.0");

        /**
         * 是否以流式接口形式返回数据
         */
        boolean stream = false;

        /**
         * 模型人设
         */
        String system = null;

        /**
         * 表示用户唯一标识符，用于监测和检测滥用行为。防止接口恶意调用。
         */
        String user_id = "";

        public void addMessage(Message message) {
            this.messages.add(message);
        }
    }

    @Data
    static class Message {
        /**
         * 用户角色
         * 目前支持：
         * user 用户
         * assistant 对话助手
         */
        String role;

        /**
         * 对话内容。
         */
        String content;

        public Message(String role, String content) {
            this.role = role;
            this.content = content;
        }
    }

    @Data
    static class QianFanResponse {
        private String id;
        private String object;
        private int created;
        private String result;
    }


}
